﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using Dimebrain.TweetSharp.Core.Extensions;
using Dimebrain.TweetSharp.Core.OAuth;

namespace Dimebrain.TweetSharp.Core.Web.Query.OAuth
{
    internal class OAuthWebQueryClient: WebClient, IWebQueryClient
    {
        public string AuthorizationHeader { get; private set; }
        public string Realm { get; set; }

        public WebResponse Response { get; private set; }
        public WebRequest Request { get; private set; }
        
        private readonly IDictionary<string, string> _headers;
        public WebParameterCollection Parameters { get; private set; }
        public string UserAgent { get; private set; }

        public OAuthWebQueryClient(IDictionary<string, string> headers, WebParameterCollection parameters, string userAgent)
        {
            _headers = headers;

            Parameters = parameters;
            UserAgent = userAgent;
        }

        public bool UseCompression { get; set; }
        public string ProxyValue { get; set; }

        public WebRequest GetWebRequestShim(Uri address)
        {
            return GetWebRequest(address);
        }

#if !SILVERLIGHT
        public WebResponse GetWebResponseShim(WebRequest request)
        {
            return GetWebResponse(request);
        }
#endif

        public WebResponse GetWebResponseShim(WebRequest request, IAsyncResult result)
        {
            return GetWebResponse(request, result);
        }

        protected override WebRequest GetWebRequest(Uri address)
        {
            //var uri = GetAddressWithOAuthParameters(address);
#if !Smartphone
            var request = (HttpWebRequest)base.GetWebRequest(address);
#else
            var request = (HttpWebRequest)WebRequest.Create(address);
#endif
            request.Method = "GET";
            request.ContentType = "application/x-www-form-urlencoded";
            
            if (_headers != null)
            {
                foreach (var header in _headers)
                {
#if !SILVERLIGHT
                    request.Headers.Add(header.Key, header.Value);
#else
                    request.Headers[header.Key] = header.Value;
#endif
                }
            }

            if (!UserAgent.IsNullOrBlank())
            {
#if !SILVERLIGHT
                request.UserAgent = UserAgent;
#else
                request.Headers["User-Agent"] = UserAgent;
#endif
            }

            if (UseCompression)
            {
#if !SILVERLIGHT
                request.AutomaticDecompression = DecompressionMethods.GZip;
#else
                request.Accept = "gzip,deflate";
#endif
            }

#if !SILVERLIGHT
            if (!ProxyValue.IsNullOrBlank())
            {
                request.Proxy = new WebProxy(ProxyValue);
                SetAuthorizationHeader(request, "Proxy-Authorization");
            }
#endif
            SetAuthorizationHeader(request);

            Request = request;
            return request;
        }

        // todo flag to remove
        private Uri GetAddressWithOAuthParameters(Uri address)
        {
            var sb = new StringBuilder("?");
            var parameters = 0;
            foreach (var parameter in Parameters)
            {
                if (parameter.Name.IsNullOrBlank() || parameter.Value.IsNullOrBlank())
                {
                    continue;
                }

                parameters++;
                var format = parameters < Parameters.Count ? "{0}={1}&" : "{0}={1}";
                sb.Append(format.FormatWith(parameter.Name, parameter.Value));
            }

            return new Uri(address + sb.ToString());
        }

        private void SetAuthorizationHeader(WebRequest request, string header)
        {
            var sb = new StringBuilder("OAuth ");
            if (!Realm.IsNullOrBlank())
            {
                sb.Append("realm=\"{0}\",".FormatWith(OAuthTools.UrlEncode(Realm)));
            }

            var parameters = 0;
            foreach (var parameter in Parameters)
            {
                if (parameter.Name.IsNullOrBlank() || parameter.Value.IsNullOrBlank())
                {
                    continue;
                }

                parameters++;
                var format = parameters < Parameters.Count ? "{0}=\"{1}\"," : "{0}=\"{1}\"";
                sb.Append(format.FormatWith(parameter.Name, parameter.Value));
            }

            var authorization = sb.ToString();
            AuthorizationHeader = authorization;

            request.Headers[header] = AuthorizationHeader;
        }

        // todo duplicated in OAuthWebQuery (for POSTS), find a better way
        private void SetAuthorizationHeader(WebRequest request)
        {
            SetAuthorizationHeader(request, "Authorization");
        }
        
#if !SILVERLIGHT
        protected override WebResponse GetWebResponse(WebRequest request)
        {
            try
            {
#if !Smartphone
                var response = base.GetWebResponse(request);
#else
                var response = request.GetResponse();
#endif
                Response = response;
                return response;
            }
            catch(WebException ex)
            {
                return HandleWebException(ex);
            }
        }
#endif

        protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
        {
            try
            {
#if !Smartphone
                var response = base.GetWebResponse(request, result);
#else
                var response = request.GetResponse();
#endif
                Response = response;
                return response;
            }
            catch(WebException ex)
            {
                return HandleWebException(ex);
            }
        }

        private static WebResponse HandleWebException(WebException ex)
        {
            if (ex.Response != null && ex.Response is HttpWebResponse)
            {
                return ex.Response;
            }

            // not the droids we're looking for
            throw ex;
        }
    }
}
